package ptij.vocoder.baseModel.preprocess;

import ptolemy.actor.*;
import ptolemy.kernel.*;
import ptolemy.kernel.util.*;
import ptolemy.data.ObjectToken;
import ptolemy.data.type.*;

import ptij.vocoder.baseModel.*;
import ptij.vocoder.baseModel.common.*;

//////////////////////////////////////////////////////////////////////////
//// FilterAndScale
/** 

@author Ivan Jeukens
@version v 0.1 07/08/2003
*/
public class FilterAndScale extends TypedAtomicActor {

    public FilterAndScale(CompositeEntity container, String name) throws
            IllegalActionException, NameDuplicationException {
        super(container, name);

        reset = new TypedIOPort(this, "reset", true, false);
        reset.setTypeEquals(BaseType.BOOLEAN);

        input = new TypedIOPort(this, "input", true, false);
        input.setTypeEquals(BaseType.OBJECT);

        output = new TypedIOPort(this, "output", false, true);
        output.setTypeEquals(BaseType.OBJECT);
    }

    ///////////////////////////////////////////////////////////////////
    ////                     ports and parameters                  ////

    // Input ports
    public TypedIOPort reset;
    public TypedIOPort input;

    // Output Ports
    public TypedIOPort output;

    ///////////////////////////////////////////////////////////////////
    ////                         public methods                    ////

    public void initialize() throws IllegalActionException {
        super.initialize();
        _init();
    }

    public void fire() throws IllegalActionException {
        if(reset.hasToken(0)) {
            reset.get(0);
            _init();
        }

        ObjectToken obj = (ObjectToken) input.get(0);
        Short [] frame = (Short []) obj.getValue();

        frame = _filter_and_scale(frame);

        output.broadcast(new ObjectToken(frame));
    }

    ///////////////////////////////////////////////////////////////////
    ////                         private methods                   ////

    private Short [] _filter_and_scale(Short [] frame) {
        int i;
        short x2;
        int L_tmp;

        Short [] ret = new Short[frame.length];

        /* filter coefficients (fc = 80 Hz, coeff. b[] is divided by 2) */
        short [] b = { 1899, -3798, 1899};
        short [] a = { 4096, 7807, -3733};

        for(i = 0; i < Cnst.L_FRAME; i++) {
            x2 = x1;
            x1 = x0;
            x0 = frame[i].shortValue();

            L_tmp = BasicOp.Mpy_32_16(y1_hi, y1_lo, a[1]);
            L_tmp = BasicOp.L_add(L_tmp, BasicOp.Mpy_32_16(y2_hi, y2_lo, a[2]));
            L_tmp = BasicOp.L_mac(L_tmp, x0, b[0]);
            L_tmp = BasicOp.L_mac(L_tmp, x1, b[1]);
            L_tmp = BasicOp.L_mac(L_tmp, x2, b[2]);
            L_tmp = BasicOp.L_shl(L_tmp, (short)3);

            ret[i] = new Short(BasicOp.round(L_tmp));

            y2_hi = y1_hi;
            y2_lo = y1_lo;
            Word32 w32 = new Word32();
            w32.hi = y1_hi;
            w32.lo = y1_lo;
            BasicOp.L_Extract(L_tmp, w32);
            y1_hi = w32.hi;
            y1_lo = w32.lo;
        }

        return ret;
    }

    private void _init() {
        y2_hi = 0;
        y2_lo = 0;
        y1_hi = 0;
        y1_lo = 0;
        x0 = 0;
        x1 = 0;
    }

    ///////////////////////////////////////////////////////////////////
    ////                         private variables                 ////

    private short y2_hi, y2_lo, y1_hi, y1_lo, x0, x1;
}
